package io.gitee.zhangbinhub.admin.workflow.controller.api

import cn.dev33.satoken.annotation.SaCheckPermission
import cn.dev33.satoken.stp.StpUtil
import io.gitee.zhangbinhub.acp.boot.exceptions.WebException
import io.gitee.zhangbinhub.acp.boot.log.LogAdapter
import io.gitee.zhangbinhub.acp.core.common.CommonTools
import io.gitee.zhangbinhub.admin.common.api.WorkFlowApi
import io.gitee.zhangbinhub.admin.common.constant.ModuleFuncCode
import io.gitee.zhangbinhub.admin.common.constant.RoleCode
import io.gitee.zhangbinhub.admin.common.vo.CustomerQueryPageVo
import io.gitee.zhangbinhub.admin.common.vo.InfoVo
import io.gitee.zhangbinhub.admin.resource.server.base.BaseResourceServerController
import io.gitee.zhangbinhub.admin.resource.server.po.*
import io.gitee.zhangbinhub.admin.resource.server.tools.TokenUserTools
import io.gitee.zhangbinhub.admin.resource.server.vo.ProcessHisTaskVo
import io.gitee.zhangbinhub.admin.resource.server.vo.ProcessInstanceVo
import io.gitee.zhangbinhub.admin.resource.server.vo.ProcessTaskVo
import io.gitee.zhangbinhub.admin.workflow.service.WorkFlowService
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
import io.swagger.v3.oas.annotations.tags.Tag
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*

@Validated
@RestController
@RequestMapping(WorkFlowApi.basePath)
@Tag(name = "工作流引擎")
class WorkFlowController @Autowired constructor(
    logAdapter: LogAdapter,
    private val tokenUserTools: TokenUserTools,
    private val workFlowService: WorkFlowService
) : BaseResourceServerController(logAdapter) {
    @Operation(summary = "启动流程", description = "启动指定的流程，并关联唯一业务主键")
    @PutMapping(value = [WorkFlowApi.start], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun start(@RequestBody @Validated processStartPo: ProcessStartPo): ResponseEntity<InfoVo> =
        tokenUserTools.getUserInfoFromToken().let { user ->
            if (CommonTools.isNullStr(user.id)) {
                throw WebException("找不到用户信息")
            }
            ResponseEntity.ok(InfoVo(message = workFlowService.startFlow(processStartPo, user.id).id.toString()))
        }

    @Operation(summary = "查询流程任务列表")
    @SaCheckPermission(ModuleFuncCode.flowAdmin, orRole = [RoleCode.SUPER])
    @GetMapping(value = [WorkFlowApi.taskList + "/{processInstanceId}"], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun taskList(@PathVariable(name = "processInstanceId") processInstanceId: Long): ResponseEntity<List<ProcessTaskVo>> =
        ResponseEntity.ok(workFlowService.findTaskList(processInstanceId))

    @Operation(summary = "查询待办任务", description = "获取当前用户的待办任务列表")
    @SaCheckPermission(ModuleFuncCode.flowPending, orRole = [RoleCode.SUPER])
    @PostMapping(value = [WorkFlowApi.pending], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun pending(@RequestBody @Validated processTaskQueryPo: ProcessTaskQueryPo): ResponseEntity<CustomerQueryPageVo<ProcessTaskVo>> =
        ResponseEntity.ok(workFlowService.findTaskList(StpUtil.getLoginIdAsString(), processTaskQueryPo))

    @Operation(summary = "转办任务", description = "转办指定的任务")
    @SaCheckPermission(ModuleFuncCode.flowProcess, orRole = [RoleCode.SUPER])
    @PatchMapping(
        value = [WorkFlowApi.transfer + "/{taskId}/{userId}"],
        produces = [MediaType.APPLICATION_JSON_VALUE]
    )
    @Throws(WebException::class)
    fun transfer(
        @Parameter(name = "任务ID", required = true)
        @PathVariable(name = "taskId") taskId: Long,
        @Parameter(name = "目标userId", required = true)
        @PathVariable(name = "userId") userId: String
    ): ResponseEntity<InfoVo> =
        workFlowService.transfer(StpUtil.getLoginIdAsString(), taskId, userId).let {
            ResponseEntity.ok(InfoVo(message = "任务已转办"))
        }

    @Operation(summary = "转办任务", description = "转办指定的任务")
    @SaCheckPermission(ModuleFuncCode.flowAdmin, orRole = [RoleCode.SUPER])
    @PatchMapping(
        value = [WorkFlowApi.distribute + "/{taskId}/{userId}"],
        produces = [MediaType.APPLICATION_JSON_VALUE]
    )
    @Throws(WebException::class)
    fun transferAdmin(
        @Parameter(name = "任务ID", required = true)
        @PathVariable(name = "taskId") taskId: Long,
        @Parameter(name = "目标userId", required = true)
        @PathVariable(name = "userId") userId: String
    ): ResponseEntity<InfoVo> =
        workFlowService.transferAdmin(StpUtil.getLoginIdAsString(), taskId, userId).let {
            ResponseEntity.ok(InfoVo(message = "任务已转办"))
        }

    @Operation(summary = "委托办理任务", description = "委托办理指定的任务")
    @SaCheckPermission(ModuleFuncCode.flowProcess, orRole = [RoleCode.SUPER])
    @PatchMapping(
        value = [WorkFlowApi.depute + "/{taskId}/{acceptUserId}"],
        produces = [MediaType.APPLICATION_JSON_VALUE]
    )
    @Throws(WebException::class)
    fun depute(
        @Parameter(name = "任务ID", required = true)
        @PathVariable(name = "taskId") taskId: Long,
        @Parameter(name = "接收userId", required = true)
        @PathVariable(name = "acceptUserId") acceptUserId: String
    ): ResponseEntity<InfoVo> = workFlowService.depute(StpUtil.getLoginIdAsString(), taskId, acceptUserId).let {
        ResponseEntity.ok(InfoVo(message = "任务已委托办理"))
    }

    @Operation(summary = "任务加签")
    @SaCheckPermission(ModuleFuncCode.flowProcess, orRole = [RoleCode.SUPER])
    @PatchMapping(
        value = [WorkFlowApi.addSignature + "/{taskId}/{acceptUserId}"],
        produces = [MediaType.APPLICATION_JSON_VALUE]
    )
    @Throws(WebException::class)
    fun addSignature(
        @Parameter(name = "任务ID", required = true)
        @PathVariable(name = "taskId") taskId: Long,
        @Parameter(name = "加签userId", required = true)
        @PathVariable(name = "acceptUserId") acceptUserId: String
    ): ResponseEntity<InfoVo> = workFlowService.addSignature(StpUtil.getLoginIdAsString(), taskId, acceptUserId).let {
        ResponseEntity.ok(InfoVo(message = "任务已加签"))
    }

    @Operation(summary = "任务减签")
    @SaCheckPermission(ModuleFuncCode.flowProcess, orRole = [RoleCode.SUPER])
    @PatchMapping(
        value = [WorkFlowApi.reductionSignature + "/{taskId}/{acceptUserId}"],
        produces = [MediaType.APPLICATION_JSON_VALUE]
    )
    @Throws(WebException::class)
    fun reductionSignature(
        @Parameter(name = "任务ID", required = true)
        @PathVariable(name = "taskId") taskId: Long,
        @Parameter(name = "减签userId", required = true)
        @PathVariable(name = "acceptUserId") acceptUserId: String
    ): ResponseEntity<InfoVo> =
        workFlowService.reductionSignature(StpUtil.getLoginIdAsString(), taskId, acceptUserId).let {
            ResponseEntity.ok(InfoVo(message = "任务已减签"))
        }

    @Operation(summary = "流程处理", description = "可选通过或不通过")
    @SaCheckPermission(ModuleFuncCode.flowProcess, orRole = [RoleCode.SUPER])
    @PostMapping(value = [WorkFlowApi.process], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun process(
        @RequestBody @Validated processHandlingPo: ProcessHandlingPo
    ): ResponseEntity<InfoVo> = tokenUserTools.getUserInfoFromToken().let { user ->
        if (CommonTools.isNullStr(user.id)) {
            throw WebException("找不到用户信息")
        }
        workFlowService.skip(processHandlingPo, user.id!!).let {
            ResponseEntity.ok(InfoVo(message = "流程处理完成"))
        }
    }

    @Operation(summary = "流程强制结束")
    @SaCheckPermission(ModuleFuncCode.flowProcess, orRole = [RoleCode.SUPER])
    @DeleteMapping(value = [WorkFlowApi.termination], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun termination(
        @RequestBody @Validated processTerminationPo: ProcessTerminationPo
    ): ResponseEntity<InfoVo> =
        tokenUserTools.getUserInfoFromToken().let { user ->
            if (CommonTools.isNullStr(user.id)) {
                throw WebException("找不到用户信息")
            }
            workFlowService.findProcessInstance(processTerminationPo.processInstanceId!!).let { instance ->
                if (instance.finished) {
                    false
                } else {
                    when {
                        hasAuthentication(mutableListOf(ModuleFuncCode.flowAdmin)) -> {
                            true
                        }

                        else -> {
                            instance.startUser != null && !CommonTools.isNullStr(instance.startUser!!.id) && instance.startUser!!.id == user.id
                        }
                    }
                }
            }.let {
                if (it) {
                    workFlowService.terminationFlow(processTerminationPo, user.id).let {
                        ResponseEntity.ok(InfoVo(message = "强制结束流程实例成功"))
                    }
                } else {
                    throw WebException("流程已结束或当前登录人不是流程发起人，无法终止该流程！")
                }
            }
        }

    @Operation(summary = "获取流程实例", description = "获取指定流程实例")
    @GetMapping(value = [WorkFlowApi.instance + "/{processInstanceId}"], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun queryInstance(
        @Parameter(name = "流程实例id", required = true)
        @PathVariable(name = "processInstanceId") processInstanceId: Long
    ): ResponseEntity<ProcessInstanceVo> = ResponseEntity.ok(workFlowService.findProcessInstance(processInstanceId))

    @Operation(summary = "获取流程实例", description = "获取流程实例")
    @PostMapping(value = [WorkFlowApi.instance], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun queryInstance(@RequestBody @Validated processQueryPo: ProcessQueryPo): ResponseEntity<CustomerQueryPageVo<ProcessInstanceVo>> =
        ResponseEntity.ok(workFlowService.findProcessInstance(processQueryPo))

    @Operation(summary = "获取我处理过的流程实例", description = "获取我处理过的流程实例")
    @PostMapping(value = [WorkFlowApi.myProcess], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun queryInstanceForMyProcess(
        @RequestBody @Validated myProcessQueryPo: MyProcessQueryPo
    ): ResponseEntity<CustomerQueryPageVo<ProcessInstanceVo>> =
        ResponseEntity.ok(
            workFlowService.findProcessInstanceForMyProcess(
                StpUtil.getLoginIdAsString(),
                myProcessQueryPo
            )
        )

    @Operation(summary = "获取流程历史记录", description = "获取指定流程实例的历史处理记录")
    @GetMapping(value = [WorkFlowApi.history + "/{processInstanceId}"], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun queryHisTask(
        @Parameter(name = "流程实例id", required = true)
        @PathVariable(name = "processInstanceId") processInstanceId: Long
    ): ResponseEntity<List<ProcessHisTaskVo>> = ResponseEntity.ok(workFlowService.findHistoryTask(processInstanceId))

    @Operation(summary = "获取流程任务信息", description = "获取指定流程任务")
    @SaCheckPermission(ModuleFuncCode.flowProcess, orRole = [RoleCode.SUPER])
    @GetMapping(value = [WorkFlowApi.task + "/{taskId}"], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun queryTaskInfo(
        @Parameter(name = "流程任务ID", required = true)
        @PathVariable(name = "taskId") taskId: Long
    ): ResponseEntity<ProcessTaskVo> =
        ResponseEntity.ok(workFlowService.findTaskById(StpUtil.getLoginIdAsString(), taskId))
}
